Table of Contents

  • 1  Preamble
    • 1.1  Imports
    • 1.2  Lists
    • 1.3  Formatting functions
    • 1.4  API call functions
  • 2  Data aquisition
    • 2.1  Fetch online data
    • 2.2  Format data
    • 2.3  Save data
  • 3  Check changes
    • 3.1  Load latest file
    • 3.2  Generate changelog
  • 4  Data visualisation
    • 4.1  Full data
    • 4.2  Card types
    • 4.3  Monsters
      • 4.3.1  Attributes
      • 4.3.2  Primary types
        • 4.3.2.1  Has effect discrimination
        • 4.3.2.2  Is pendulum discrimination
        • 4.3.2.3  By attribute
      • 4.3.3  Secondary types
        • 4.3.3.1  By attribute
        • 4.3.3.2  By secondary type
      • 4.3.4  Monster types
        • 4.3.4.1  By Attribute
        • 4.3.4.2  By primary type
        • 4.3.4.3  By secondary type
      • 4.3.5  Effect type
      • 4.3.6  ATK
      • 4.3.7  DEF
      • 4.3.8  Level/Rank
        • 4.3.8.1  ATK statistics
        • 4.3.8.2  DEF statistics
      • 4.3.9  Pendulum scale
        • 4.3.9.1  ATK statistics
        • 4.3.9.2  DEF statistics
        • 4.3.9.3  Level/Rank statistics
      • 4.3.10  Link
        • 4.3.10.1  ATK statistics
      • 4.3.11  Link Arrows
        • 4.3.11.1  By combination
        • 4.3.11.2  By unique
        • 4.3.11.3  By link
    • 4.4  Spell & Trap
      • 4.4.1  Properties
      • 4.4.2  Effect type
        • 4.4.2.1  Spell & Trap discrimination
    • 4.5  Archseries
      • 4.5.1  By card type
      • 4.5.2  By primary type
      • 4.5.3  By secondary type
      • 4.5.4  By monster type
      • 4.5.5  By property
    • 4.6  Artworks
      • 4.6.1  By card type
      • 4.6.2  By primary type
    • 4.7  Errata
      • 4.7.1  By card type
      • 4.7.2  By primary type
      • 4.7.3  By artwork
    • 4.8  TCG & OCG status
      • 4.8.1  TGC status
        • 4.8.1.1  By card type
        • 4.8.1.2  By monster type
        • 4.8.1.3  By archseries
      • 4.8.2  OCG status
        • 4.8.2.1  By card type
        • 4.8.2.2  By monster type
        • 4.8.2.3  By archseries
      • 4.8.3  TCG vs. OCG status
  • 5  HTML export
  • 6  Searches

Preamble¶

Imports¶

import glob
import os
import pandas as pd
import numpy as np
import seaborn as sns
%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm, Normalize
from matplotlib_venn import venn2
from datetime import datetime
from ast import literal_eval

Lists¶

# Attributes to split monsters query
attributes = ['DIVINE', 'LIGHT', 'DARK', 'WATER', 'EARTH', 'FIRE', 'WIND']

# API variables
api_url = 'https://yugipedia.com/api.php'

# Styling dictionaries
arrows_dict = {'Middle-Left': '\u2190', 'Middle-Right': '\u2192', 'Top-Left': '\u2196', 'Top-Center': '\u2191', 'Top-Right': '\u2197', 'Bottom-Left': '\u2199', 'Bottom-Center': '\u2193', 'Bottom-Right': '\u2198'}
card_colors = {'Effect Monster': '#FF8B53', 'Normal Monster': '#FDE68A', 'Ritual Monster': '#9DB5CC', 'Fusion Monster': '#A086B7', 'Synchro Monster': '#CCCCCC', 'Xyz Monster': '#000000', 'Link Monster': '#00008B', 'Pendulum Monster': 'r', 'Monster Card': '#FF8B53', 'Spell Card': '#1D9E74', 'Trap Card': '#BC5A84', 'Monster Token': '#C0C0C0', 'FIRE': '#fd1b1b', 'WATER': '#03a9e6', 'EARTH': '#060d0a', 'WIND': '#77bb58', 'DARK': '#745ea5', 'LIGHT': '#9d8047', 'DIVINE': '#7e6537', 'Level': '#f1a41f'}

Formatting functions¶

def extract_results(df):
    df = pd.DataFrame(df['query']['results']).transpose()
    df = pd.DataFrame(df['printouts'].values.tolist())
    return df

def extract_artwork(row):
    result = tuple()
    if 'Category:OCG/TCG cards with alternate artworks' in row:
        result += ('Alternate',)
    if 'Category:OCG/TCG cards with edited artworks' in row:
        result += ('Edited',)
    if result == tuple():
        return np.nan
    else:
        return result

def concat_errata(row):
    result = tuple()
    if row['Name errata']:
        result += ('Name',)
    if row['Type errata']:
        result += ('Type',)
    if result == tuple():
        return np.nan
    else:
        return result 
    
def format_df(input_df, input_errata_df):
    df = pd.DataFrame()
    if 'Name' in input_df.columns:
        df['Name'] = input_df['Name'].dropna().apply(lambda x: x[0])
    if 'Password' in input_df.columns:
        df['Password'] = input_df['Password'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Card type' in input_df.columns:
        df['Card type'] = input_df['Card type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Property' in input_df.columns:
        df['Property'] = input_df['Property'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Primary type' in input_df.columns:
        df['Primary type'] = input_df['Primary type'].dropna().apply(lambda x: [i['fulltext'] for i in x] if len(x)>0 else []).apply(lambda y: list(filter(lambda z: z != 'Pendulum Monster', y)) if len(y)>0 else []).apply(lambda y: list(filter(lambda z: z != 'Effect Monster', y))[0] if len(y)>1 else (y[0] if len(y)>0 else np.nan))
    if 'Secondary type' in input_df.columns:
        df['Secondary type'] = input_df['Secondary type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Attribute' in input_df.columns:
        df['Attribute'] = input_df['Attribute'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Monster type' in input_df.columns:
        df['Monster type'] = input_df['Monster type'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Level/Rank' in input_df.columns:
        df['Level/Rank'] = input_df['Level/Rank'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'ATK' in input_df.columns:
        df['ATK'] = input_df['ATK'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'DEF' in input_df.columns:
        df['DEF'] = input_df['DEF'].dropna().apply(lambda x: x[0] if len(x)>0 else np.nan)
    if 'Pendulum Scale' in input_df.columns:
        df['Pendulum Scale'] = input_df['Pendulum Scale'].dropna().apply(lambda x: str(x[0]) if len(x)>0 else np.nan)
    if 'Link' in input_df.columns:
        df['Link'] = input_df['Link'].dropna().apply(lambda x: str(x[0]) if len(x)>0 else np.nan)
    if 'Link Arrows' in input_df.columns:
        df['Link Arrows'] = input_df['Link Arrows'].dropna().apply(lambda x: tuple([arrows_dict[i] for i in sorted(x)]) if len(x)>0 else np.nan)
    if 'Effect type' in input_df.columns:
        df['Effect type'] = input_df['Effect type'].dropna().apply(lambda x: tuple(sorted([i['fulltext'] for i in x])) if len(x)>0 else np.nan)
    if 'Archseries' in input_df.columns:
        df['Archseries'] = input_df['Archseries'].dropna().apply(lambda x: tuple(sorted(x)) if len(x)>0 else np.nan)
    if 'Category' in input_df.columns:
        df['Artwork'] = input_df['Category'].dropna().apply(lambda x: [i['fulltext'] for i in x] if len(x)>0 else np.nan).apply(extract_artwork)
    # Erratas column
    if input_errata_df is not None and 'Page name' in input_df.columns:
        df['Errata'] = errata_df.merge(input_df['Page name'].dropna().apply(lambda x: x[0]).rename('Name'), right_on = 'Name', left_index = True).apply(concat_errata,axis = 1)
    #################
    if 'TCG status' in input_df.columns:
        df['TCG status'] = input_df['TCG status'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'OCG status' in input_df.columns:
        df['OCG status'] = input_df['OCG status'].dropna().apply(lambda x: x[0]['fulltext'] if len(x)>0 else np.nan)
    if 'Modification date' in input_df.columns:
        df['Modification date'] = input_df['Modification date'].dropna().apply(lambda x: pd.Timestamp(int(x[0]['timestamp']), unit='s').ctime() if len(x)>0 else np.nan)
    
    return df

API call functions¶

def card_query(_password = True, _card_type = True, _property = True, _primary = True, _secondary = True, _attribute = True, _monster_type = True, _stars = True, _atk = True, _def = True, _scale = True, _link = True, _arrows = True, _effect_type = True, _archseries = True, _category = True, _tcg = True, _ocg = True, _date = True, _page_name = True):
    search_string = f'|?English%20name=Name'
    if _password:
        search_string += '|?Password'
    if _card_type:
        search_string += '|?Card%20type'
    if _property:    
        search_string += '|?Property'
    if _primary:
        search_string += '|?Primary%20type'
    if _secondary:
        search_string += '|?Secondary%20type'
    if _attribute:
        search_string += '|?Attribute'
    if _monster_type:
        search_string += '|?Type=Monster%20type'
    if _stars:
        search_string += '|?Stars%20string=Level%2FRank%20'
    if _atk:
        search_string += '|?ATK%20string=ATK'
    if _def:
        search_string += '|?DEF%20string=DEF'
    if _scale:
        search_string += '|?Pendulum%20Scale'
    if _link:
        search_string += '|?Link%20Rating=Link'
    if _arrows:
        search_string += '|?Link%20Arrows'
    if _effect_type:
        search_string += '|?Effect%20type'
    if _archseries:
        search_string += '|?Archseries'
    if _category:
        search_string += '|?category'
    if _tcg:
        search_string += '|?TCG%20status'
    if _ocg:
        search_string += '|?OCG%20status'
    if _date:
        search_string += '|?Modification%20date'
    if _page_name:
        search_string += '|?Page%20name'
    
    return search_string

def fetch_spell(spell_query, step = 5000, limit = 5000):
    print('Downloading Spells')
    spell_df = pd.DataFrame()
    for i in range(int(limit/step)):
        df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20Spell%20Cards]]{spell_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
        df = extract_results(df)
        print(f'Iteration {i+1}: {len(df.index)} results')
        spell_df = pd.concat([spell_df, df], ignore_index=True, axis=0)
        if len(df.index)<step:
            break
                
    print(f'- Total\n{len(spell_df.index)} results\n')
    
    return spell_df

def fetch_trap(trap_query, step = 5000, limit = 5000):
    print('Downloading Traps')
    trap_df = pd.DataFrame()
    for i in range(int(limit/step)):    
        df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20Trap%20Cards]]{trap_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
        df = extract_results(df)
        print(f'Iteration {i+1}: {len(df.index)} results')
        trap_df = pd.concat([trap_df, df], ignore_index=True, axis=0)
        if len(df.index)<step:
            break
                
    print(f'- Total\n{len(trap_df.index)} results\n')
    
    return trap_df

def fetch_monster(monster_query, step = 5000, limit = 5000):
    print('Downloading Monsters')
    monster_df = pd.DataFrame()
    for att in attributes:
        print(f"- {att}")
        for i in range(int(limit/step)):
            df = pd.read_json(f'{api_url}?action=ask&query=[[Concept:CG%20monsters]][[Attribute::{att}]]{monster_query}|limit%3D{step}|offset={i*step}|order%3Dasc&format=json')
            df = extract_results(df)
            print(f'Iteration {i+1}: {len(df.index)} results')
            monster_df = pd.concat([monster_df, df], ignore_index=True, axis=0)
            if len(df.index)<step:
                break
        
    print(f'- Total\n{len(monster_df.index)} results')
    
    return monster_df

def fetch_name_errata(limit = 1000):
    name_query_df = pd.read_json(f'{api_url}?action=ask&query=[[Category:Cards%20with%20name%20errata]]|limit={limit}|order%3Dasc&format=json')
    name_keys = list(name_query_df['query']['results'].keys())
    return pd.DataFrame(True, index = [i.split(':')[1].strip() for i in name_keys if 'Card Errata:' in i], columns = ['Name errata'])

def fetch_type_errata(limit = 1000):
    type_query_df = pd.read_json(f'{api_url}?action=ask&query=[[Category:Cards%20with%20card%20type%20errata]]|limit={limit}|order%3Dasc&format=json')
    type_keys = list(type_query_df['query']['results'].keys())
    return pd.DataFrame(True, index = [i.split(':')[1].strip() for i in type_keys if 'Card Errata:' in i], columns = ['Type errata'])

Data aquisition¶

Fetch online data¶

monster_query = card_query(_property = False)
st_query = card_query(_primary = False, _secondary = False, _attribute = False, _monster_type = False, _stars = False, _atk = False, _def = False, _scale = False, _link = False, _arrows = False)
# Timestamp
timestamp = pd.Timestamp.now().timestamp()
full_df = pd.DataFrame()

# Fetch Spell
spell_df = fetch_spell(st_query, step = 1000, limit = 3000)
full_df = pd.concat([full_df, spell_df], ignore_index=True, axis=0)

# Fetch Trap
trap_df = fetch_trap(st_query, step = 1000, limit = 3000)
full_df = pd.concat([full_df, trap_df], ignore_index=True, axis=0)
st_df = pd.concat([spell_df, trap_df], ignore_index=True, axis=0)

# Fetch Monster
monster_df = fetch_monster(monster_query, step = 1000, limit = 5000)
full_df = pd.concat([full_df, monster_df], ignore_index=True, axis=0)

# Fetch errata
errata_df = pd.concat([fetch_name_errata(), fetch_type_errata()], axis=1).fillna(False)
Downloading Spells
Iteration 1: 1000 results
Iteration 2: 1000 results
Iteration 3: 346 results
- Total
2346 results

Downloading Traps
Iteration 1: 1000 results
Iteration 2: 794 results
- Total
1794 results

Downloading Monsters
- DIVINE
Iteration 1: 9 results
- LIGHT
Iteration 1: 1000 results
Iteration 2: 613 results
- DARK
Iteration 1: 1000 results
Iteration 2: 1000 results
Iteration 3: 203 results
- WATER
Iteration 1: 826 results
- EARTH
Iteration 1: 1000 results
Iteration 2: 854 results
- FIRE
Iteration 1: 659 results
- WIND
Iteration 1: 757 results
- Total
7921 results

Format data¶

formatted_spell_df = format_df(spell_df, errata_df)
formatted_trap_df = format_df(trap_df, errata_df)
formatted_st_df = format_df(st_df, errata_df)
formatted_monster_df = format_df(monster_df, errata_df)
formatted_full_df = format_df(full_df, errata_df)
print('Data formated')
Data formated

Save data¶

formatted_full_df.to_csv(f'Data/All_cards_{int(timestamp)}.csv', index = False)
print('Data saved')
Data saved

Check changes¶

Load latest file¶

# Get list of files
list_of_files = sorted(glob.glob('Data/All_cards_*.csv'), key=os.path.getctime, reverse=True)
# Get second newest file if exist
if len(list_of_files)>1:
    latest_file = list_of_files[1]
    previous_df = pd.read_csv(latest_file, dtype=object)
    # Correct tuples
    previous_df['Effect type'] = previous_df['Effect type'].dropna().apply(literal_eval)
    previous_df['Link Arrows'] = previous_df['Link Arrows'].dropna().apply(literal_eval)
    previous_df['Archseries'] = previous_df['Archseries'].dropna().apply(literal_eval)
    previous_df['Artwork'] = previous_df['Artwork'].dropna().apply(literal_eval)
    previous_df['Errata'] = previous_df['Errata'].dropna().apply(literal_eval)
    print('File loaded')
else:
    print('No older files')
File loaded

Generate changelog¶

if previous_df is not None:
    changelog = previous_df.merge(formatted_full_df,indicator = True, how='outer').loc[lambda x : x['_merge']!='both'].sort_values('Name', ignore_index=True)
    changelog['_merge'].replace(['left_only','right_only'],['Old', 'New'], inplace = True)
    changelog.rename(columns={"_merge": "Version"}, inplace = True)
    nunique = changelog.groupby('Name').nunique()
    cols_to_drop = nunique[nunique < 2].dropna(axis=1).columns
    changelog = changelog.set_index('Name')[nunique > 1]
    changelog.drop(cols_to_drop, axis=1, inplace = True)
    changelog
else:
    print('No changes')

Data visualisation¶

Full data¶

formatted_full_df
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK ... Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
0 "A" Cell Breeding Device 34541863 Spell Card Continuous Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Trigger Effect,) NaN NaN (Name,) Unlimited Unlimited Sat Nov 6 13:57:15 2021
1 "A" Cell Incubator 64163367 Spell Card Continuous Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Continuous-like Effect, Trigger Effect) NaN NaN NaN Unlimited Unlimited Mon Jun 13 04:27:51 2022
2 "A" Cell Recombination Device 91231901 Spell Card Quick-Play Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Effect, Ignition-like Effect) NaN NaN NaN Unlimited Unlimited Thu Mar 12 22:40:14 2020
3 "A" Cell Scatter Burst 73262676 Spell Card Quick-Play Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Effect,) NaN NaN NaN Unlimited Unlimited Sat Nov 6 13:58:32 2021
4 "Infernoble Arms - Durendal" 37478723 Spell Card Equip Spell Card NaN NaN NaN NaN NaN NaN ... NaN NaN NaN (Condition, Ignition-like Effect, Trigger Effect) (Noble Arms,) NaN NaN Unlimited Unlimited Sat Aug 20 13:52:48 2022
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
12056 Yosenju Shinchu L 65025250 Monster Card NaN Effect Monster NaN WIND Rock 4 0 ... 3 NaN NaN (Continuous Effect, Continuous-like Effect, Tr... (Yosenju,) NaN NaN Unlimited Unlimited Sun Aug 14 11:04:00 2022
12057 Yosenju Shinchu R 91420254 Monster Card NaN Effect Monster NaN WIND Rock 4 0 ... 5 NaN NaN (Continuous Effect, Ignition-like Effect, Trig... (Yosenju,) NaN NaN Unlimited Unlimited Sat Aug 13 12:21:48 2022
12058 Yosenju Tsujik 25244515 Monster Card NaN Effect Monster NaN WIND Beast-Warrior 4 1000 ... NaN NaN NaN (Condition, Ignition Effect, Quick Effect, Tri... (Yosenju,) NaN NaN Unlimited Unlimited Sun Dec 20 18:15:02 2020
12059 ZW - Eagle Claw 29353756 Monster Card NaN Effect Monster NaN WIND Winged Beast 5 2000 ... NaN NaN NaN (Continuous-like Effect, Ignition Effect, Uncl... (ZW -, Zexal) NaN NaN Unlimited Unlimited Thu Jul 8 13:48:07 2021
12060 ZW - Tornado Bringer 81471108 Monster Card NaN Effect Monster NaN WIND Dragon 5 1300 ... NaN NaN NaN (Continuous-like Effect, Ignition Effect, Uncl... (ZW -, Zexal) NaN NaN Unlimited Unlimited Sun Aug 14 11:04:24 2022

12061 rows × 21 columns

Card types¶

formatted_full_df.groupby('Card type').nunique()
Name Password Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Card type
Monster Card 7913 7813 0 8 6 7 25 15 82 77 13 6 61 222 977 3 3 7 7 7871
Spell Card 2344 2331 6 0 0 0 0 0 0 0 0 0 0 114 392 3 3 6 6 2335
Trap Card 1794 1779 3 0 0 0 0 0 0 0 0 0 0 95 323 3 3 6 6 1788
card_type_colors = [card_colors[i] for i in formatted_full_df['Card type'].value_counts().index]
formatted_full_df['Card type'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=0, color = card_type_colors)
plt.show()

Monsters¶

Attributes¶

print('Total number of attributes:', formatted_monster_df['Attribute'].nunique())
Total number of attributes: 7
formatted_monster_df.drop(columns=['Card type']).groupby('Attribute').nunique()
Name Password Primary type Secondary type Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Attribute
DARK 2200 2173 7 6 23 14 70 63 12 6 39 153 443 3 3 7 7 2196
DIVINE 6 0 1 0 2 2 3 3 0 0 0 6 3 1 3 2 2 9
EARTH 1852 1838 7 6 23 12 71 59 11 4 29 124 322 3 3 5 6 1845
FIRE 659 657 8 6 22 12 43 40 8 4 22 83 183 3 3 3 5 657
LIGHT 1613 1574 7 6 23 14 58 50 10 5 30 131 381 3 3 7 6 1605
WATER 826 820 7 6 22 11 56 41 9 4 16 92 201 3 3 6 6 826
WIND 757 751 7 6 23 12 46 38 11 4 14 104 211 3 3 5 6 753
attribute_colors = [card_colors[i] for i in formatted_full_df['Attribute'].value_counts().index]
formatted_monster_df['Attribute'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=0, color = attribute_colors)
plt.show()

Primary types¶

print('Total number of primary types:', formatted_monster_df['Primary type'].nunique())
Total number of primary types: 8
formatted_monster_df.drop(columns=['Card type']).groupby('Primary type').nunique()
Name Password Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Primary type
Effect Monster 5379 5341 6 7 25 12 73 66 13 0 0 203 762 3 3 5 6 5351
Fusion Monster 420 419 1 6 23 12 48 46 3 0 0 66 138 3 3 4 4 419
Link Monster 364 358 0 6 23 0 38 0 0 6 61 51 138 3 2 5 4 364
Monster Token 1 0 0 1 1 1 1 1 0 0 0 0 1 0 0 0 1 1
Normal Monster 745 701 1 6 23 10 59 49 10 0 0 6 128 3 3 4 4 746
Ritual Monster 118 117 3 6 15 12 33 26 1 0 0 33 37 2 3 2 2 118
Synchro Monster 404 400 1 6 23 13 40 38 4 0 0 55 154 2 3 4 5 404
Xyz Monster 486 477 0 6 23 14 51 42 4 0 0 66 189 3 2 4 5 484

Has effect discrimination¶

has_effect = formatted_monster_df['Primary type'].where(formatted_monster_df['Effect type'].notna()).value_counts().rename('Effect')
no_effect = formatted_monster_df['Primary type'].where(formatted_monster_df['Effect type'].isna()).value_counts().rename('No Effect')
effect = pd.concat([has_effect,no_effect], axis=1)
effect
Effect No Effect
Effect Monster 5379.0 NaN
Xyz Monster 484.0 2.0
Synchro Monster 401.0 3.0
Link Monster 359.0 5.0
Fusion Monster 358.0 62.0
Ritual Monster 102.0 16.0
Normal Monster 34.0 712.0
Monster Token NaN 1.0
monster_type_colors = {'No Effect': card_colors['Normal Monster'], 'Effect': [card_colors[i] for i in effect.index]}
effect.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0,  legend=True, color = monster_type_colors)
plt.show()

Normal monster can have effect if it is pendulum

Is pendulum discrimination¶

not_pendulum = formatted_monster_df['Primary type'].where(formatted_monster_df['Pendulum Scale'].isna()).value_counts().rename('Not Pendulum')
is_pendulum = formatted_monster_df['Primary type'].where(formatted_monster_df['Pendulum Scale'].notna()).value_counts().rename('Pendulum')
pendulum = pd.concat([not_pendulum,is_pendulum], axis=1)
pendulum
Not Pendulum Pendulum
Effect Monster 5118 261.0
Normal Monster 708 38.0
Xyz Monster 479 7.0
Fusion Monster 411 9.0
Synchro Monster 399 5.0
Link Monster 364 NaN
Ritual Monster 117 1.0
Monster Token 1 NaN
monster_type_colors_b = {'Pendulum': card_colors['Pendulum Monster'], 'Not Pendulum': [card_colors[i] for i in pendulum.index]}
pendulum.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0, color = monster_type_colors_b, legend=True)
plt.show()

By attribute¶

primmary_crosstab = pd.crosstab(formatted_full_df['Primary type'],formatted_full_df['Attribute'])
primmary_crosstab
Attribute DARK DIVINE EARTH FIRE LIGHT WATER WIND
Primary type
Effect Monster 1481 6 1287 446 1089 546 524
Fusion Monster 144 0 79 34 96 34 33
Link Monster 117 0 74 33 86 29 25
Monster Token 0 0 0 1 0 0 0
Normal Monster 186 0 250 52 82 109 67
Ritual Monster 35 0 17 7 33 20 6
Synchro Monster 107 0 67 50 74 33 73
Xyz Monster 133 0 80 36 153 55 29
plt.figure(figsize = (16,10))
sns.heatmap(primmary_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Secondary types¶

print('Total number of secondary types:', formatted_monster_df['Secondary type'].nunique())
Total number of secondary types: 6
formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Secondary type').nunique()
Name Password Primary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Effect type Archseries Artwork Errata TCG status OCG status Modification date
Secondary type
Flip monster 183 182 2 6 19 12 38 33 1 20 44 2 3 3 4 183
Gemini monster 45 45 1 6 18 8 17 19 0 6 13 0 3 1 1 45
Spirit monster 37 37 2 6 13 9 22 20 2 7 4 1 1 2 2 37
Toon monster 17 17 1 6 7 5 12 15 0 8 13 1 2 1 2 17
Tuner monster 464 461 5 6 23 9 32 32 7 57 131 3 3 3 5 463
Union monster 37 37 1 6 9 8 17 14 0 6 9 1 2 1 1 37
secondary_type_colors = card_colors['Effect Monster']
formatted_monster_df['Secondary type'].value_counts().plot.bar(figsize = (18,6), stacked = True, grid = True, rot=0, color = secondary_type_colors, legend=True)
plt.show()

By attribute¶

secondary_crosstab = pd.crosstab(formatted_full_df['Secondary type'],formatted_full_df['Attribute'])
secondary_crosstab
Attribute DARK EARTH FIRE LIGHT WATER WIND
Secondary type
Flip monster 51 61 10 31 13 17
Gemini monster 11 8 8 6 8 4
Spirit monster 5 6 6 4 6 10
Toon monster 7 5 1 2 1 1
Tuner monster 119 91 42 94 50 68
Union monster 6 9 3 12 4 3
plt.figure(figsize = (8,6))
sns.heatmap(secondary_crosstab, annot=True, fmt="g", cmap='viridis', square=True)
plt.show()

By secondary type¶

secondary_crosstab_b = pd.crosstab(formatted_full_df['Primary type'],formatted_full_df['Secondary type'], margins = True)
secondary_crosstab_b
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster All
Primary type
Effect Monster 182 45 35 17 418 37 734
Fusion Monster 0 0 0 0 3 0 3
Normal Monster 0 0 0 0 12 0 12
Ritual Monster 1 0 2 0 1 0 4
Synchro Monster 0 0 0 0 30 0 30
All 183 45 37 17 464 37 783
plt.figure(figsize = (10,7))
sns.heatmap(secondary_crosstab_b, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Monster types¶

print('Total number of monster types:', formatted_monster_df['Monster type'].nunique())
Total number of monster types: 25
formatted_monster_df.drop(columns=['Card type']).groupby('Monster type').nunique()
Name Password Primary type Secondary type Attribute Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Monster type
Aqua 254 252 7 6 6 10 50 33 3 2 3 51 64 2 3 3 3 254
Beast 375 367 7 4 6 10 48 38 7 2 7 59 82 3 3 4 6 376
Beast-Warrior 236 232 7 3 6 10 36 29 6 3 7 57 47 3 3 4 5 235
Creator God 1 0 1 0 1 1 1 1 0 0 0 1 1 0 0 0 1 1
Cyberse 246 244 7 1 6 11 30 29 1 6 38 45 34 2 2 3 4 246
Dinosaur 121 120 6 1 6 10 35 30 4 2 3 35 24 1 2 3 3 121
Divine-Beast 5 0 1 0 1 1 3 3 0 0 0 5 2 1 3 2 2 8
Dragon 654 647 7 6 6 13 52 48 9 5 19 109 184 2 3 6 6 651
Fairy 505 497 7 5 6 12 43 38 8 4 12 78 109 3 3 6 5 501
Fiend 759 746 7 6 6 13 60 45 12 5 14 106 147 3 3 6 5 758
Fish 122 121 7 2 5 10 34 28 1 1 1 30 21 2 2 2 3 122
Insect 236 235 7 3 6 12 44 33 2 3 6 55 39 2 2 2 3 236
Machine 911 900 7 5 6 12 62 55 9 4 22 111 165 3 3 5 7 905
Plant 230 228 6 4 6 9 37 30 5 4 9 38 38 2 2 3 4 230
Psychic 175 173 6 2 6 11 35 31 5 2 3 41 40 1 2 4 5 175
Pyro 121 120 7 5 5 11 34 29 0 1 1 36 33 1 3 1 3 121
Reptile 171 170 6 3 6 11 37 30 3 2 3 46 35 0 2 4 3 171
Rock 246 244 7 4 6 11 43 39 4 3 4 59 72 1 3 5 5 245
Sea Serpent 82 82 6 3 6 10 28 26 1 2 2 32 28 2 3 2 2 82
Spellcaster 673 662 7 5 6 12 49 40 10 5 12 100 146 3 3 5 6 671
Thunder 128 125 6 4 6 10 35 29 1 2 4 37 33 1 2 3 4 128
Warrior 1022 1015 7 6 6 13 60 41 6 3 15 92 214 3 3 6 7 1020
Winged Beast 312 309 7 5 6 10 39 29 4 4 6 61 65 2 3 4 4 312
Wyrm 86 85 6 1 6 11 26 24 3 4 6 32 20 1 1 4 3 86
Zombie 242 239 7 5 6 12 38 37 1 3 5 51 35 2 3 1 3 241
monster_type_colors = card_colors['Monster Card']
formatted_monster_df['Monster type'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=45, color = monster_type_colors)
plt.show()

By Attribute¶

monster_crosstab = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Attribute'], dropna=False)
monster_crosstab
Attribute DARK DIVINE EARTH FIRE LIGHT WATER WIND
Monster type
Aqua 9 0 6 10 4 219 6
Beast 37 0 212 16 72 14 25
Beast-Warrior 37 0 82 53 33 16 15
Creator God 0 1 0 0 0 0 0
Cyberse 63 0 36 44 63 28 12
Dinosaur 11 0 59 32 5 8 6
Divine-Beast 0 8 0 0 0 0 0
Dragon 251 0 47 48 167 28 113
Fairy 55 0 60 15 324 26 25
Fiend 573 0 33 46 70 23 16
Fish 2 0 2 0 1 115 2
Insect 37 0 127 6 20 4 42
Machine 222 0 308 50 167 48 116
Plant 42 0 118 11 22 24 13
Psychic 23 0 36 17 45 12 42
Pyro 2 0 6 106 4 0 3
Reptile 39 0 34 15 45 34 4
Rock 16 0 198 5 15 5 7
Sea Serpent 3 0 1 1 2 71 4
Spellcaster 281 0 53 28 187 63 62
Thunder 13 0 10 5 77 4 19
Warrior 202 0 363 100 245 53 60
Winged Beast 109 0 7 16 15 12 153
Wyrm 15 0 18 10 23 12 8
Zombie 161 0 38 25 7 7 4
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True)
plt.show()

By primary type¶

monster_crosstab_b = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Primary type'], dropna=False)
monster_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Monster Token Normal Monster Ritual Monster Synchro Monster Xyz Monster
Monster type
Aqua 153 11 3 0 59 8 3 17
Beast 270 17 9 0 54 1 14 11
Beast-Warrior 162 11 9 0 21 2 8 23
Creator God 1 0 0 0 0 0 0 0
Cyberse 122 4 93 0 7 6 5 9
Dinosaur 86 7 3 0 18 0 4 3
Divine-Beast 5 0 0 0 0 0 0 0
Dragon 345 62 33 0 46 15 93 60
Fairy 360 20 24 0 36 17 17 31
Fiend 532 46 27 0 79 15 22 40
Fish 88 5 1 0 17 1 7 3
Insect 174 2 9 0 29 1 7 14
Machine 633 46 38 0 67 4 60 63
Plant 161 6 15 0 25 0 7 16
Psychic 118 11 5 0 9 0 19 13
Pyro 84 8 1 1 18 0 5 4
Reptile 140 1 3 0 19 0 5 3
Rock 168 18 4 0 28 7 5 16
Sea Serpent 55 2 2 0 8 0 5 10
Spellcaster 510 25 26 0 55 17 16 25
Thunder 97 8 5 0 11 0 5 2
Warrior 671 93 29 0 80 14 54 82
Winged Beast 227 8 9 0 27 4 15 22
Wyrm 54 2 9 0 3 0 10 8
Zombie 163 7 7 0 30 6 18 11
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square=True, norm = LogNorm())
plt.show()

By secondary type¶

monster_crosstab_c = pd.crosstab(formatted_full_df['Monster type'],formatted_full_df['Secondary type'], dropna=False)
monster_crosstab_c
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster
Monster type
Aqua 4 4 1 1 10 3
Beast 15 1 2 0 22 0
Beast-Warrior 1 0 1 0 9 0
Cyberse 0 0 0 0 6 0
Dinosaur 0 0 0 0 7 0
Dragon 1 6 1 3 42 4
Fairy 8 2 7 0 20 5
Fiend 27 4 2 1 41 1
Fish 0 1 0 0 7 0
Insect 20 2 0 0 11 0
Machine 10 1 0 4 80 18
Plant 4 1 0 0 20 1
Psychic 3 0 0 0 23 0
Pyro 4 2 2 0 8 1
Reptile 18 1 0 0 7 0
Rock 11 1 2 0 3 0
Sea Serpent 1 1 0 0 9 0
Spellcaster 33 3 4 4 39 0
Thunder 3 1 1 0 8 0
Warrior 11 9 5 3 30 3
Winged Beast 5 2 7 1 30 0
Wyrm 0 0 0 0 10 0
Zombie 4 3 2 0 22 1
plt.figure(figsize = (20,5))
sns.heatmap(monster_crosstab_c.T, annot=True, fmt="g", cmap='viridis', square=True, norm = LogNorm())
plt.show()

Effect type¶

print('Total number of effect types:', formatted_monster_df['Effect type'].explode().nunique())
Total number of effect types: 14
formatted_monster_df[formatted_monster_df['Effect type'].notna()].drop(columns=['Card type']).explode('Effect type').groupby('Effect type').nunique()
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Archseries Artwork Errata TCG status OCG status Modification date
Effect type
Activation condition 1 1 1 0 1 1 1 1 1 1 0 0 1 0 0 1 1 1
Condition 3002 2953 7 6 7 25 14 63 63 13 5 53 629 3 3 5 6 2987
Continuous Effect 2126 2115 6 5 7 24 14 59 52 12 6 48 552 3 3 4 4 2124
Continuous-like Effect 233 233 6 3 6 21 11 42 36 13 1 2 72 2 3 3 2 233
Flip effect 169 168 1 1 6 19 12 38 33 1 0 0 42 2 3 3 4 169
Ignition Effect 2569 2553 6 6 7 24 13 66 61 12 5 42 629 3 3 5 6 2559
Ignition-like Effect 214 208 6 2 6 20 12 35 32 13 1 1 73 1 3 3 4 214
Lingering effect 16 16 2 1 6 11 7 11 13 0 2 2 9 0 0 2 1 16
Maintenance cost 44 44 3 0 6 12 8 21 18 2 1 1 8 0 1 1 1 44
Quick Effect 994 991 6 4 6 23 13 50 47 8 5 28 384 3 3 5 4 993
Quick-like Effect 4 4 1 0 1 1 1 3 2 0 0 0 1 0 0 1 1 4
Summoning condition 904 864 6 4 7 25 13 52 51 8 5 6 312 3 3 6 5 900
Trigger Effect 4258 4240 7 6 7 24 14 66 62 13 5 49 752 3 3 4 6 4235
Unclassified effect 804 795 6 5 7 25 13 49 45 9 5 12 270 3 3 3 4 802
monster_effect_colors = card_colors['Effect Monster']
formatted_monster_df['Effect type'].explode('Effect type').value_counts().plot.bar(figsize = (18,6), grid = True, color = monster_effect_colors)
plt.show()

ATK¶

print('Total number of ATK values:', formatted_monster_df['ATK'].nunique())
Total number of ATK values: 82
formatted_monster_df.drop(columns=['Card type']).groupby('ATK').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
ATK
0 609 584 8 5 6 23 13 35 9 5 15 92 232 3 3 5 6 608
50 2 2 1 0 2 2 1 2 0 0 0 2 2 0 0 1 1 2
100 216 216 5 3 6 20 11 27 8 2 2 48 106 2 3 2 2 216
150 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1
200 118 116 6 5 6 20 7 21 4 1 2 34 67 2 3 2 4 118
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4500 12 12 3 0 3 6 4 4 0 0 0 10 9 1 1 1 1 12
4600 2 2 1 0 2 1 1 1 0 0 0 2 1 0 0 1 1 2
5000 9 9 5 0 3 4 2 4 0 1 1 8 6 1 1 1 1 9
? 83 75 6 1 7 20 15 8 2 1 1 34 36 2 3 4 4 84
X000 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 1 1

82 rows × 18 columns

atk_colors = card_colors['Monster Card']
formatted_monster_df['DEF'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, color = atk_colors)
plt.show()

DEF¶

print('Total number of DEF values:', formatted_monster_df['DEF'].nunique())
Total number of DEF values: 77
formatted_monster_df.drop(columns=['Card type']).groupby('DEF').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
DEF
0 764 737 7 6 6 23 14 45 10 0 0 104 258 3 3 5 5 761
50 1 1 1 0 1 1 1 1 0 0 0 1 1 0 0 1 1 1
100 207 206 5 4 6 19 10 24 8 0 0 46 94 2 3 3 3 206
200 248 245 5 5 6 23 10 31 5 0 0 47 107 3 3 3 5 248
250 8 8 2 1 4 5 2 4 0 0 0 5 3 0 1 1 1 8
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4500 2 2 2 0 2 2 1 1 0 0 0 2 1 0 0 1 1 2
4800 1 1 1 0 1 1 1 1 0 0 0 1 1 0 0 1 1 1
5000 5 5 2 0 3 3 2 2 0 0 0 4 3 1 1 1 1 5
? 56 49 5 1 7 17 14 2 1 0 0 25 25 2 3 4 4 57
X000 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 1 1 1

77 rows × 18 columns

def_colors = card_colors['Monster Card']
formatted_monster_df['DEF'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, color = def_colors)
plt.show()

Level/Rank¶

formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Level/Rank').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type ATK DEF Pendulum Scale Effect type Archseries Artwork Errata TCG status OCG status Modification date
Level/Rank
0 6 6 2 0 2 2 3 3 0 5 3 0 0 2 2 6
1 627 601 7 5 6 23 22 29 10 80 227 3 3 4 5 625
2 670 660 6 5 6 23 29 30 7 73 212 3 3 4 6 669
3 1142 1136 6 5 6 23 41 36 9 92 289 3 3 4 7 1142
4 2321 2312 6 6 6 23 54 47 9 134 501 3 3 4 7 2314
5 591 591 6 6 6 23 46 38 8 83 233 3 3 3 3 591
6 601 597 6 6 6 23 38 38 9 92 232 3 3 5 6 602
7 462 457 6 6 6 23 37 35 9 99 220 3 3 4 5 463
8 664 647 6 5 6 23 42 41 8 110 298 3 3 4 5 665
9 139 138 5 2 6 21 30 27 1 54 85 1 3 4 3 139
10 244 231 5 2 7 22 32 33 6 75 146 2 3 3 4 247
11 31 30 6 2 6 13 16 17 1 22 23 0 1 3 2 31
12 49 48 5 1 6 12 12 16 2 31 36 1 2 2 2 49
13 1 1 1 0 1 1 1 1 0 1 1 0 0 1 1 1
? 1 0 1 0 1 1 1 1 0 0 0 0 0 0 1 1
stars_colors = card_colors['Level']
formatted_monster_df['Level/Rank'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color= stars_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Level/Rank','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Level/Rank').describe()
ATK
count mean std min 25% 50% 75% max
Level/Rank
0 5.0 600.000000 1341.640786 0.0 0.0 0.0 0.0 3000.0
1 617.0 239.789303 352.151718 0.0 0.0 100.0 300.0 2500.0
2 668.0 583.308383 408.935775 0.0 300.0 500.0 800.0 2400.0
3 1139.0 958.955224 485.391745 0.0 600.0 1000.0 1300.0 3000.0
4 2309.0 1418.419229 540.251213 0.0 1200.0 1500.0 1800.0 3000.0
5 588.0 1765.765306 638.460344 0.0 1500.0 1900.0 2200.0 4000.0
6 598.0 2012.792642 615.312202 0.0 1900.0 2200.0 2400.0 4000.0
7 458.0 2290.502183 610.943569 0.0 2200.0 2500.0 2600.0 3300.0
8 656.0 2550.228659 707.632830 0.0 2500.0 2800.0 3000.0 4500.0
9 136.0 2594.485294 851.005349 0.0 2500.0 2800.0 3000.0 4500.0
10 224.0 2824.330357 1219.607927 0.0 2800.0 3000.0 3500.0 5000.0
11 30.0 2990.000000 1093.113238 0.0 3000.0 3350.0 3500.0 4000.0
12 45.0 3355.555556 1429.964328 0.0 3000.0 4000.0 4000.0 5000.0

DEF statistics¶

formatted_monster_df[['Level/Rank','DEF']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Level/Rank').describe()
DEF
count mean std min 25% 50% 75% max
Level/Rank
0 5.0 400.000000 894.427191 0.0 0.0 0.0 0.0 2000.0
1 619.0 337.883683 519.434793 0.0 0.0 100.0 400.0 2500.0
2 669.0 660.837070 555.314459 0.0 200.0 500.0 900.0 2400.0
3 1139.0 954.784899 571.624287 0.0 600.0 900.0 1300.0 3000.0
4 2311.0 1169.506707 606.262069 0.0 800.0 1200.0 1600.0 3000.0
5 589.0 1421.731749 673.303655 0.0 1000.0 1500.0 1900.0 3000.0
6 598.0 1560.418060 708.831576 0.0 1200.0 1700.0 2000.0 3000.0
7 460.0 1881.521739 652.359443 0.0 1600.0 2000.0 2300.0 3300.0
8 663.0 1975.263952 845.964589 0.0 1600.0 2100.0 2500.0 4000.0
9 136.0 2306.250000 799.431221 0.0 2000.0 2500.0 3000.0 3700.0
10 233.0 2230.686695 1281.773909 0.0 1900.0 2500.0 3000.0 5000.0
11 30.0 2661.666667 1169.415071 0.0 2125.0 3000.0 3400.0 4000.0
12 46.0 2852.173913 1672.089728 0.0 2000.0 3350.0 4000.0 5000.0

Pendulum scale¶

formatted_monster_df.drop(columns=['Card type', 'Link', 'Link Arrows']).groupby('Pendulum Scale').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Effect type Archseries Artwork Errata TCG status OCG status Modification date
Pendulum Scale
0 10 10 2 1 5 7 6 5 5 8 8 1 0 1 1 10
1 67 64 5 2 6 10 11 28 26 37 38 0 1 3 4 67
2 36 36 2 1 6 11 6 17 22 21 15 0 2 3 2 36
3 36 36 2 1 6 15 8 22 15 23 17 0 0 1 1 36
4 32 32 5 0 5 8 8 18 16 25 16 1 1 1 1 32
5 34 34 2 1 6 12 7 23 21 20 16 0 1 3 3 34
6 15 15 1 1 4 7 6 11 11 11 9 0 0 1 1 15
7 27 27 2 1 6 14 6 19 17 14 16 0 2 1 1 27
8 39 39 5 1 6 9 8 19 18 23 21 0 0 1 2 39
9 8 8 2 1 3 3 5 3 2 5 3 0 0 1 1 8
10 14 11 5 0 6 6 5 6 8 11 8 0 0 2 2 14
12 2 2 1 0 1 2 2 2 2 2 2 0 0 1 1 2
13 1 1 1 0 1 1 1 1 1 1 1 0 0 1 1 1
scales_colors = card_colors['Pendulum Monster']
formatted_monster_df['Pendulum Scale'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color = scales_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Pendulum Scale','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
ATK
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 1390.000000 1317.784336 0.0 0.0 1450.0 2500.0 3000.0
1 66.0 1751.515152 1053.381723 0.0 1000.0 1800.0 2500.0 4000.0
2 36.0 1423.611111 688.734462 100.0 800.0 1500.0 2000.0 2500.0
3 36.0 1437.500000 845.354955 0.0 600.0 1725.0 2025.0 2600.0
4 32.0 1787.500000 1011.785391 0.0 1100.0 2000.0 2550.0 3000.0
5 34.0 1339.705882 808.831875 0.0 850.0 1325.0 1800.0 3450.0
6 15.0 1320.000000 707.308783 100.0 950.0 1500.0 1800.0 2400.0
7 27.0 1279.629630 787.920737 0.0 700.0 1400.0 1750.0 3000.0
8 39.0 1225.641026 968.644726 0.0 300.0 1200.0 2000.0 3300.0
9 8.0 2150.000000 730.948503 1000.0 2050.0 2400.0 2500.0 2800.0
10 14.0 1678.571429 1376.829452 0.0 125.0 2500.0 2875.0 3000.0
12 1.0 100.000000 NaN 100.0 100.0 100.0 100.0 100.0
13 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

DEF statistics¶

formatted_monster_df[['Pendulum Scale','DEF']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
DEF
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 1200.000000 1273.664878 0.0 0.0 750.0 2500.0 3000.0
1 67.0 1571.641791 940.310389 0.0 950.0 1700.0 2350.0 4000.0
2 36.0 1338.888889 728.316171 0.0 875.0 1200.0 1825.0 2700.0
3 36.0 1165.277778 788.834533 0.0 575.0 1200.0 1800.0 3000.0
4 32.0 1534.375000 830.316448 0.0 1000.0 1600.0 2075.0 2800.0
5 34.0 1136.764706 822.625953 0.0 550.0 1000.0 1575.0 3000.0
6 15.0 1226.666667 711.604492 400.0 600.0 1100.0 1700.0 2600.0
7 27.0 1312.962963 830.383669 0.0 700.0 1300.0 2000.0 2700.0
8 39.0 1015.384615 789.916205 0.0 350.0 1000.0 1700.0 2700.0
9 8.0 1225.000000 636.396103 1000.0 1000.0 1000.0 1000.0 2800.0
10 14.0 1850.000000 1124.380171 0.0 750.0 2500.0 2575.0 3000.0
12 1.0 100.000000 NaN 100.0 100.0 100.0 100.0 100.0
13 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

Level/Rank statistics¶

formatted_monster_df[['Pendulum Scale','Level/Rank']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Pendulum Scale').describe()
Level/Rank
count mean std min 25% 50% 75% max
Pendulum Scale
0 10.0 6.100000 3.348300 1.0 3.75 7.0 8.00 10.0
1 67.0 5.955224 2.427324 1.0 4.00 6.0 8.00 12.0
2 36.0 4.416667 1.380993 1.0 3.75 4.0 5.00 7.0
3 36.0 4.444444 1.731134 1.0 4.00 4.0 5.00 10.0
4 32.0 5.562500 2.154328 1.0 4.00 6.0 7.00 8.0
5 34.0 4.176471 1.961301 1.0 3.00 4.0 4.00 11.0
6 15.0 3.933333 1.579632 1.0 3.00 4.0 4.50 8.0
7 27.0 4.185185 1.641693 2.0 3.00 4.0 5.00 10.0
8 39.0 3.923077 2.355113 1.0 2.00 4.0 6.00 10.0
9 8.0 5.625000 1.302470 4.0 5.00 5.0 6.25 8.0
10 14.0 6.714286 2.812843 1.0 7.00 7.0 7.75 10.0
12 2.0 6.500000 7.778175 1.0 3.75 6.5 9.25 12.0
13 1.0 7.000000 NaN 7.0 7.00 7.0 7.00 7.0

Link¶

formatted_monster_df.drop(columns=['Card type', 'Primary type', 'Secondary type','Level/Rank','DEF','Pendulum Scale']).groupby('Link').nunique().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce'))
Name Password Attribute Monster type ATK Link Arrows Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link
1 47 47 6 11 10 8 17 26 1 0 3 3 47
2 183 183 6 23 23 19 31 101 1 2 4 3 183
3 81 81 6 16 17 17 25 46 2 1 2 2 81
4 44 41 6 16 12 13 21 24 2 0 3 4 44
5 8 5 2 5 4 3 5 4 0 0 2 2 8
6 1 1 1 1 1 1 1 1 0 0 1 1 1
link_colors = card_colors['Link Monster']
formatted_monster_df['Link'].value_counts().sort_index(key=lambda x: pd.to_numeric(x, errors = 'coerce')).plot.bar(figsize = (18,6), grid = True, rot=0, color = link_colors)
plt.show()

ATK statistics¶

formatted_monster_df[['Link','ATK']].apply(pd.to_numeric, errors = 'coerce').dropna().astype(int).groupby('Link').describe()
ATK
count mean std min 25% 50% 75% max
Link
1 47.0 736.170213 482.937358 0.0 400.0 800.0 1000.0 1500.0
2 183.0 1399.726776 509.349328 0.0 1100.0 1500.0 1800.0 2300.0
3 81.0 2258.641975 659.487970 0.0 2200.0 2400.0 2500.0 4000.0
4 43.0 2660.465116 653.976676 0.0 2500.0 2800.0 3000.0 3300.0
5 8.0 3250.000000 755.928946 2500.0 3000.0 3000.0 3125.0 5000.0
6 1.0 0.000000 NaN 0.0 0.0 0.0 0.0 0.0

Link Arrows¶

By combination¶

print('Total number of link arrow combinations:', formatted_monster_df['Link Arrows'].nunique())
Total number of link arrow combinations: 61
formatted_monster_df.drop(columns=['Card type', 'Primary type', 'Level/Rank', 'Pendulum Scale', 'Link', 'Secondary type', 'DEF']).groupby('Link Arrows').nunique()
Name Password Attribute Monster type ATK Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link Arrows
(←,) 5 5 2 3 2 4 4 0 0 3 2 5
(←, ↑) 4 4 2 3 4 3 2 0 0 1 1 4
(←, →) 18 18 6 8 11 8 9 0 0 2 2 18
(←, →, ↑) 7 7 3 5 6 6 5 0 0 1 1 7
(↑,) 10 10 5 5 6 9 5 0 0 1 1 10
... ... ... ... ... ... ... ... ... ... ... ... ...
(↙, ↘, ←, ↖) 1 1 1 1 1 1 1 0 0 1 1 1
(↙, ↘, ↑) 22 22 6 11 11 11 15 1 1 2 2 22
(↙, ↘, →) 2 2 2 2 2 2 2 0 0 1 1 2
(↙, ↘, ↖) 2 2 2 2 2 2 0 0 0 1 1 2
(↙, ↘, ↖, ↗) 1 1 1 1 1 1 1 0 0 1 1 1

61 rows × 12 columns

arrows_colors = card_colors['Link Monster']
formatted_monster_df['Link Arrows'].value_counts().plot.bar(figsize = (18,6), logy=True, grid = True, color = arrows_colors)
plt.show()

By unique¶

formatted_monster_df[formatted_monster_df['Link Arrows'].notna()].drop(columns=['Card type', 'Primary type', 'Level/Rank', 'Pendulum Scale', 'Secondary type', 'DEF']).explode('Link Arrows').groupby('Link Arrows').nunique()
Name Password Attribute Monster type ATK Link Effect type Archseries Artwork Errata TCG status OCG status Modification date
Link Arrows
← 113 107 6 21 29 6 34 45 2 0 5 3 113
↑ 114 111 6 19 27 6 31 44 2 1 3 4 114
→ 99 93 6 19 27 6 29 40 2 0 3 3 99
↓ 156 150 6 20 31 6 41 68 3 0 4 4 156
↖ 10 10 5 5 9 4 6 5 1 0 1 2 10
↗ 15 15 5 7 10 5 7 7 0 0 1 2 15
↘ 184 181 6 22 32 6 35 102 3 2 4 4 184
↙ 187 184 6 22 33 6 37 103 3 2 4 4 187
arrows_colors_b = card_colors['Link Monster']
formatted_monster_df['Link Arrows'].explode('Link Arrows').value_counts().plot.bar(figsize = (18,6), grid = True, color = arrows_colors_b)
plt.show()

By link¶

arrow_per_link = formatted_monster_df[['Link Arrows','Link']].explode('Link Arrows').dropna()
arrow_crosstab = pd.crosstab(arrow_per_link['Link Arrows'],arrow_per_link['Link'])
arrow_crosstab
Link 1 2 3 4 5 6
Link Arrows
← 5 47 23 30 7 1
↑ 10 28 43 28 4 1
→ 2 33 24 31 8 1
↓ 18 59 41 32 5 1
↖ 1 2 5 2 0 0
↗ 3 5 3 3 1 0
↘ 3 94 53 25 8 1
↙ 5 98 51 25 7 1
plt.figure(figsize = (10,6))
sns.heatmap(arrow_crosstab.T, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

Spell & Trap¶

Properties¶

print('Total number of properties:', formatted_st_df['Property'].nunique())
Total number of properties: 9
formatted_st_df.drop(columns=['Card type']).groupby('Property').nunique()
Name Password Effect type Archseries Artwork Errata TCG status OCG status Modification date
Property
Continuous Spell Card 414 412 53 156 3 3 6 5 412
Continuous Trap Card 487 479 63 160 2 3 4 2 487
Counter Trap Card 154 152 19 58 2 2 2 2 154
Equip Spell Card 262 262 37 74 1 3 2 2 262
Field Spell Card 269 266 35 142 2 3 6 4 270
Normal Spell Card 906 902 43 226 3 3 5 6 907
Normal Trap Card 1153 1148 48 237 3 2 5 6 1148
Quick-Play Spell Card 418 415 34 137 3 3 4 3 418
Ritual Spell Card 75 74 8 25 2 2 1 2 75
st_colors = [card_colors[i] for i in formatted_full_df[['Card type','Property']].value_counts().index.get_level_values(0)]
formatted_st_df['Property'].value_counts().plot.bar(figsize = (18,6), grid = True, rot=45, color = st_colors)
plt.show()

Effect type¶

print('Total number of effect types:', formatted_st_df['Effect type'].explode().nunique())
Total number of effect types: 14
formatted_st_df.explode('Effect type').groupby('Effect type').nunique()
Name Password Card type Property Archseries Artwork Errata TCG status OCG status Modification date
Effect type
Activation condition 832 825 2 8 171 3 3 4 5 831
Condition 1637 1621 2 9 367 3 3 6 5 1628
Continuous Effect 21 21 2 6 12 0 2 1 1 21
Continuous-like Effect 890 883 2 7 233 3 3 6 4 890
Cost 452 450 2 7 112 3 3 4 4 452
Effect 2893 2871 2 9 424 3 3 6 6 2879
Ignition Effect 2 2 2 2 2 0 0 1 1 2
Ignition-like Effect 427 425 1 6 178 1 2 5 5 426
Lingering effect 94 94 2 6 41 2 2 3 3 94
Maintenance cost 22 22 2 5 7 1 1 3 3 22
Quick Effect 9 9 2 3 4 0 0 1 1 9
Quick-like Effect 331 326 2 4 146 2 1 4 4 331
Trigger Effect 830 824 2 9 255 2 3 4 5 825
Unclassified effect 83 83 2 9 48 1 0 1 2 82

Spell & Trap discrimination¶

spell = formatted_spell_df['Effect type'].explode('Effect type').value_counts().rename('Spell Card')
trap = formatted_trap_df['Effect type'].explode('Effect type').value_counts().rename('Trap Card')
st_diff = pd.concat([spell, trap], axis = 1)
st_diff
Spell Card Trap Card
Effect 1504 1390.0
Condition 1110 528.0
Continuous-like Effect 611 280.0
Trigger Effect 556 274.0
Ignition-like Effect 427 NaN
Activation condition 244 588.0
Cost 241 211.0
Unclassified effect 63 20.0
Lingering effect 56 38.0
Maintenance cost 11 11.0
Continuous Effect 7 14.0
Quick Effect 4 5.0
Quick-like Effect 3 328.0
Ignition Effect 1 1.0
st_diff_colors = {'Spell Card': card_colors['Spell Card'], 'Trap Card': card_colors['Trap Card']}
st_diff.plot.bar(figsize = (18,6), stacked = True, grid = True, rot=45, color = st_diff_colors)
plt.show()

Archseries¶

exploded_archseries = formatted_full_df.explode('Archseries')
print('Total number of Archseries:', exploded_archseries['Archseries'].nunique())
Total number of Archseries: 706
exploded_archseries.groupby('Archseries').nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Artwork Errata TCG status OCG status Modification date
Archseries
"C" 8 8 1 0 2 0 1 1 7 8 8 0 0 0 6 0 1 2 1 8
-Eyes Dragon 72 71 1 0 7 2 6 3 10 16 13 6 1 1 44 1 3 2 3 71
/Assault Mode 7 7 1 0 1 0 5 6 5 6 6 0 0 0 5 0 0 1 1 7
@Ignister 18 18 1 0 6 1 6 1 7 10 9 0 3 4 9 0 0 1 1 18
A-to-Z 16 16 1 0 3 1 1 1 4 13 12 0 0 0 5 2 3 1 2 16
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
sphinx 10 10 2 1 1 0 2 2 4 8 5 0 0 0 9 0 0 1 1 10
sprout 2 2 1 0 1 0 1 1 1 1 1 0 0 0 2 0 0 1 1 2
tellarknight 21 21 2 3 2 0 2 3 2 16 14 2 0 0 11 0 0 2 2 21
with Chain 4 4 1 1 0 0 0 0 0 0 0 0 0 0 4 1 0 1 1 4
with Eyes of Blue 8 8 2 2 1 1 1 1 1 3 4 0 0 0 6 0 1 1 1 8

706 rows × 20 columns

exploded_archseries['Archseries'].value_counts().plot.barh(figsize = (10,200), grid = True)
plt.show()

By card type¶

archseries_crosstab = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Card type'], margins = True)
archseries_crosstab
Card type Monster Card Spell Card Trap Card All
Archseries
"C" 8 0 0 8
-Eyes Dragon 72 0 0 72
/Assault Mode 7 0 0 7
@Ignister 18 0 0 18
A-to-Z 16 0 0 16
... ... ... ... ...
sprout 2 0 0 2
tellarknight 17 4 0 21
with Chain 0 0 4 4
with Eyes of Blue 5 3 0 8
All 7223 1337 889 9449

707 rows × 4 columns

By primary type¶

archseries_crosstab_b = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Primary type'], margins = True)
archseries_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Monster Token Normal Monster Ritual Monster Synchro Monster Xyz Monster All
Archseries
"C" 7 0 0 0 1 0 0 0 8
-Eyes Dragon 31 11 1 0 3 4 5 17 72
/Assault Mode 7 0 0 0 0 0 0 0 7
@Ignister 10 1 4 0 0 1 1 1 18
A-to-Z 6 8 0 0 2 0 0 0 16
... ... ... ... ... ... ... ... ... ...
sphinx 9 0 0 0 0 0 0 0 9
sprout 2 0 0 0 0 0 0 0 2
tellarknight 12 0 0 0 0 0 0 5 17
with Eyes of Blue 5 0 0 0 0 0 0 0 5
All 4638 527 329 1 243 119 433 929 7219

644 rows × 9 columns

By secondary type¶

archseries_crosstab_c = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Secondary type'], margins = True)
archseries_crosstab_c
Secondary type Flip monster Gemini monster Spirit monster Toon monster Tuner monster Union monster All
Archseries
-Eyes Dragon 0 2 0 2 0 0 4
@Ignister 0 0 0 0 1 0 1
A-to-Z 0 0 0 0 0 6 6
Adamancipator 0 0 0 0 3 0 3
Alien 1 1 0 0 1 0 3
... ... ... ... ... ... ... ...
itsu 0 0 0 0 0 2 2
lswarm 2 0 0 0 0 0 2
roid 0 0 0 0 9 0 9
with Eyes of Blue 0 0 0 0 5 0 5
All 125 28 13 36 414 18 634

195 rows × 7 columns

By monster type¶

archseries_crosstab_d = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Monster type'], margins = True)
archseries_crosstab_d
Monster type Aqua Beast Beast-Warrior Creator God Cyberse Dinosaur Divine-Beast Dragon Fairy Fiend ... Reptile Rock Sea Serpent Spellcaster Thunder Warrior Winged Beast Wyrm Zombie All
Archseries
"C" 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 8
-Eyes Dragon 0 0 0 0 0 0 0 67 0 0 ... 0 0 0 0 0 0 0 0 3 72
/Assault Mode 0 0 0 0 0 0 0 2 0 0 ... 0 0 0 1 0 1 0 0 1 7
@Ignister 0 0 0 0 18 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 18
A-to-Z 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 16
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
sphinx 0 3 0 0 0 0 0 0 0 0 ... 0 6 0 0 0 0 0 0 0 9
sprout 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 2
tellarknight 0 0 0 0 0 0 0 0 0 1 ... 0 0 0 0 0 15 0 1 0 17
with Eyes of Blue 0 0 0 0 0 0 0 0 0 0 ... 0 0 0 5 0 0 0 0 0 5
All 193 286 183 2 149 81 12 717 442 694 ... 138 213 71 577 95 1236 267 76 158 7223

644 rows × 26 columns

By property¶

archseries_crosstab_e = pd.crosstab(exploded_archseries['Archseries'],exploded_archseries['Property'], margins = True)
archseries_crosstab_e
Property Continuous Spell Card Continuous Trap Card Counter Trap Card Equip Spell Card Field Spell Card Normal Spell Card Normal Trap Card Quick-Play Spell Card Ritual Spell Card All
Archseries
A.I. 1 3 0 0 1 4 1 2 1 13
Abyss Actor 0 0 0 0 0 0 2 0 0 2
Abyss Script 1 0 0 0 0 4 0 1 0 6
Abyss- 0 1 0 3 0 0 3 0 0 7
Adamancipator 0 0 1 0 1 2 1 0 0 5
... ... ... ... ... ... ... ... ... ... ...
sphinx 0 1 0 0 0 0 0 0 0 1
tellarknight 0 0 0 1 1 0 0 2 0 4
with Chain 0 0 0 0 0 0 4 0 0 4
with Eyes of Blue 1 0 0 0 0 0 0 2 0 3
All 238 286 72 130 176 502 531 253 38 2226

395 rows × 10 columns

Artworks¶

print('Total number of cards with edited or alternate artworks:', formatted_full_df['Artwork'].count())
Total number of cards with edited or alternate artworks: 422
formatted_full_df[['Name','Password','TCG status','OCG status','Artwork']][formatted_full_df['Artwork'].notna()]
Name Password TCG status OCG status Artwork
51 Alluring Mirror Split 92881099 Unlimited Unlimited (Alternate, Edited)
60 Amazoness Spellcaster 81325903 Unlimited Unlimited (Edited,)
69 Ancient Gear Castle 92001300 Unlimited Unlimited (Edited,)
116 Arrivalrivals 29508346 Unlimited Unlimited (Alternate, Edited)
135 Axe of Despair 40619825 Unlimited Unlimited (Edited,)
... ... ... ... ... ...
11881 Soitsu 60246171 Unlimited Unlimited (Edited,)
11932 Stardust Dragon 44508094 Unlimited Unlimited (Alternate,)
11940 Storming Wynn 29013526 Unlimited Unlimited (Alternate, Edited)
11967 Thousand Dragon 41462083 Unlimited Unlimited (Alternate,)
11969 Toon Harpie Lady 64116319 Unlimited Unlimited (Edited,)

422 rows × 5 columns

artwork_value_counts = formatted_full_df['Artwork'].value_counts()
plt.figure(figsize=(20,8))
venn2(subsets = (artwork_value_counts[('Alternate',)], artwork_value_counts[('Edited',)],artwork_value_counts[('Alternate','Edited')]), set_labels = ('Alternate artwork', 'Edited artwork'))
plt.show()

By card type¶

artwork_crosstab = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Card type'])
artwork_crosstab
Card type Monster Card Spell Card Trap Card
Artwork
(Alternate,) 79 4 6
(Alternate, Edited) 80 18 20
(Edited,) 110 62 43

By primary type¶

artwork_crosstab_b = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Primary type'])
artwork_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Normal Monster Ritual Monster Synchro Monster Xyz Monster
Artwork
(Alternate,) 35 11 6 20 0 3 4
(Alternate, Edited) 39 6 7 20 4 0 4
(Edited,) 78 6 1 20 2 2 1

More granularity is unnecessary

Errata¶

print('Total number of cards with name or type errata:', formatted_full_df['Errata'].count())
Total number of cards with name or type errata: 1129
formatted_full_df[['Name','Password','TCG status','OCG status','Errata']][formatted_full_df['Errata'].notna()]
Name Password TCG status OCG status Errata
0 "A" Cell Breeding Device 34541863 Unlimited Unlimited (Name,)
9 7 Completed 86198326 Unlimited Unlimited (Type,)
10 The A. Forces 00403847 Unlimited Unlimited (Type,)
19 Abyss Playhouse - Fantastic Theater 77297908 Unlimited Unlimited (Name,)
43 Advanced Heraldry Art 61314842 Unlimited Unlimited (Name,)
... ... ... ... ... ...
12030 Winged Dragon, Guardian of the Fortress #1 87796900 Unlimited Unlimited (Name,)
12031 Winged Dragon, Guardian of the Fortress #2 57405307 Unlimited Unlimited (Name,)
12033 Winged Sage Falcos 87523462 Unlimited Unlimited (Name,)
12040 Wynn the Wind Charmer 37744402 Unlimited Unlimited (Name,)
12041 Wynn the Wind Charmer, Verdant 30674956 Unlimited Unlimited (Name,)

1129 rows × 5 columns

errata_value_counts = formatted_full_df['Errata'].value_counts()
plt.figure(figsize=(20,8))
venn2(subsets = (errata_value_counts[('Name',)], errata_value_counts[('Type',)],errata_value_counts[('Name','Type')]), set_labels = ('Name Errata', 'Type errata'))
plt.show()

By card type¶

errata_crosstab = pd.crosstab(formatted_full_df['Errata'], formatted_full_df['Card type'])
errata_crosstab
Card type Monster Card Spell Card Trap Card
Errata
(Name,) 312 57 50
(Name, Type) 73 21 2
(Type,) 396 209 9

By primary type¶

errata_crosstab_b = pd.crosstab(formatted_full_df['Errata'], formatted_full_df['Primary type'])
errata_crosstab_b
Primary type Effect Monster Fusion Monster Link Monster Normal Monster Ritual Monster Synchro Monster Xyz Monster
Errata
(Name,) 196 46 4 50 3 9 3
(Name, Type) 39 10 0 17 2 5 0
(Type,) 270 22 2 61 2 24 15

More granularity is unnecessary

By artwork¶

errata_crosstab_c = pd.crosstab(formatted_full_df['Artwork'], formatted_full_df['Errata'])
errata_crosstab_c
Errata (Name,) (Name, Type) (Type,)
Artwork
(Alternate,) 8 15 21
(Alternate, Edited) 9 6 13
(Edited,) 15 7 38

TCG & OCG status¶

TGC status¶

print('Total number of TCG status:', formatted_full_df['TCG status'].nunique())
Total number of TCG status: 7
formatted_full_df.groupby('TCG status', dropna=False).nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata OCG status Modification date
TCG status
Forbidden 99 99 3 7 5 2 6 19 12 27 21 2 4 10 46 53 2 3 4 99
Illegal 38 0 3 3 5 0 6 14 5 11 12 2 2 2 6 7 0 1 1 38
Legal 20 0 1 0 1 0 5 11 5 6 7 0 0 0 0 13 2 1 1 20
Limited 81 81 3 7 6 3 6 15 9 20 20 3 2 2 42 40 3 3 4 81
Not yet released 10 10 3 5 2 0 2 2 1 2 1 0 1 1 7 5 0 0 1 9
Semi-Limited 9 9 3 4 2 0 3 3 1 3 3 0 0 0 8 8 1 1 3 9
Unlimited 11309 11306 3 9 7 6 7 24 14 80 75 13 6 60 342 1112 3 3 4 11208
NaN 493 419 3 9 8 3 7 24 12 54 39 6 4 8 96 111 1 1 4 491
formatted_full_df['TCG status'].value_counts(dropna = False).plot.bar(figsize = (18,6), logy=True, grid = True, rot=45)
plt.show()

By card type¶

# Remove unlimited
tcg_crosstab = pd.crosstab(formatted_full_df['Card type'], formatted_full_df['TCG status']).drop(['Unlimited'], axis=1)
tcg_crosstab
TCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Card type
Monster Card 64 35 20 42 2 3
Spell Card 26 2 0 34 5 5
Trap Card 9 1 0 5 3 1
plt.figure(figsize = (12,6))
sns.heatmap(tcg_crosstab, annot=True, fmt="g", cmap='viridis', norm=LogNorm())
plt.show()

By monster type¶

# Remove unlimited
tcg_crosstab_b = pd.crosstab(formatted_full_df['Monster type'], formatted_full_df['TCG status']).drop(['Unlimited'], axis=1)
tcg_crosstab_b
TCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Monster type
Aqua 1 0 2 0 0 0
Beast 0 3 1 2 0 0
Beast-Warrior 2 3 0 2 0 0
Cyberse 2 0 0 1 0 0
Dinosaur 0 0 1 2 0 0
Divine-Beast 0 3 0 0 0 0
Dragon 10 3 1 7 1 0
Fairy 3 4 3 1 0 1
Fiend 5 2 4 3 1 0
Fish 1 0 0 0 0 0
Insect 2 0 0 0 0 0
Machine 6 4 3 6 0 0
Plant 6 1 0 0 0 0
Psychic 2 1 0 1 0 0
Pyro 0 0 0 0 0 0
Reptile 1 0 1 1 0 0
Rock 3 1 1 3 0 0
Sea Serpent 1 0 0 0 0 0
Spellcaster 7 5 1 9 0 0
Thunder 1 1 0 0 0 0
Warrior 4 2 2 2 0 1
Winged Beast 3 2 0 1 0 0
Wyrm 4 0 0 1 0 1
Zombie 0 0 0 0 0 0
plt.figure(figsize = (20,5))
sns.heatmap(tcg_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square = True, norm=LogNorm())
plt.show()

By archseries¶

# Remove unlimited
tcg_crosstab_c = pd.crosstab(exploded_archseries['Archseries'].where(exploded_archseries['OCG status']!='Unlimited'), exploded_archseries['TCG status'], margins = True)
tcg_crosstab_c
TCG status Forbidden Illegal Legal Limited Semi-Limited Unlimited All
Archseries
-Eyes Dragon 1 0 0 0 0 0 1
A-to-Z 0 0 0 0 0 1 1
Adventurer Token (series) 0 0 0 0 0 2 2
Amazoness 0 0 0 0 0 1 1
Ancient Gear 0 0 1 0 0 0 1
... ... ... ... ... ... ... ...
Zexal 1 0 0 0 0 0 1
Zoodiac 3 0 0 1 0 0 4
roid 0 0 0 1 0 0 1
tellarknight 1 0 0 0 0 0 1
All 68 40 16 29 6 51 210

119 rows × 7 columns

OCG status¶

print('Total number of OCG status:', formatted_full_df['OCG status'].nunique())
Total number of OCG status: 7
formatted_full_df.groupby('OCG status', dropna=False).nunique()
Name Password Card type Property Primary type Secondary type Attribute Monster type Level/Rank ATK DEF Pendulum Scale Link Link Arrows Effect type Archseries Artwork Errata TCG status Modification date
OCG status
Forbidden 89 89 3 6 5 4 6 19 11 28 21 3 4 7 39 44 2 3 3 89
Illegal 32 1 3 2 6 1 6 12 8 14 15 2 2 2 8 8 0 1 1 32
Legal 39 0 1 0 2 0 6 17 7 8 8 0 0 0 0 24 2 1 1 39
Limited 65 65 3 6 6 2 6 13 9 17 18 3 3 5 33 36 2 3 4 65
Not yet released 26 0 3 4 4 1 5 12 7 14 15 0 0 0 17 12 0 0 0 26
Semi-Limited 19 19 3 5 1 1 2 4 3 4 4 0 0 0 12 12 0 2 4 19
Unlimited 11759 11735 3 9 7 6 7 25 14 81 76 13 6 59 350 1136 3 3 5 11658
NaN 26 14 3 5 6 1 5 13 4 9 9 0 1 1 13 5 0 0 2 26
formatted_full_df['OCG status'].value_counts(dropna = False).plot.bar(figsize = (18,6), logy=True, grid = True, rot=45)
plt.show()

By card type¶

# Remove unlimited
ocg_crosstab = pd.crosstab(formatted_full_df['Card type'], formatted_full_df['OCG status']).drop(['Unlimited'], axis=1)
ocg_crosstab
OCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Card type
Monster Card 56 30 39 37 19 4
Spell Card 22 1 0 26 5 14
Trap Card 11 1 0 2 2 1
plt.figure(figsize = (12,6))
sns.heatmap(ocg_crosstab, annot=True, fmt="g", cmap='viridis', norm=LogNorm())
plt.show()

By monster type¶

# Remove unlimited
ocg_crosstab_b = pd.crosstab(formatted_full_df['Monster type'], formatted_full_df['OCG status']).drop(['Unlimited'], axis=1)
ocg_crosstab_b
OCG status Forbidden Illegal Legal Limited Not yet released Semi-Limited
Monster type
Aqua 2 0 2 0 0 0
Beast 1 2 4 0 1 1
Beast-Warrior 3 2 0 1 0 1
Creator God 0 0 0 0 0 0
Cyberse 2 0 2 1 0 0
Dinosaur 0 0 1 1 0 0
Divine-Beast 0 3 0 0 0 0
Dragon 10 3 1 4 3 0
Fairy 2 3 4 1 0 0
Fiend 6 1 7 0 4 0
Fish 1 0 0 0 1 0
Insect 1 0 0 0 1 0
Machine 4 3 6 8 1 1
Plant 5 0 1 1 0 0
Psychic 1 1 0 3 1 0
Pyro 0 0 1 1 0 0
Reptile 1 0 1 0 0 0
Rock 1 1 1 2 0 0
Sea Serpent 1 0 0 0 0 0
Spellcaster 7 7 1 10 3 0
Thunder 0 0 1 2 1 0
Warrior 4 3 3 2 1 1
Winged Beast 2 1 1 0 0 0
Wyrm 2 0 0 0 1 0
Zombie 0 0 2 0 1 0
plt.figure(figsize = (20,5))
sns.heatmap(ocg_crosstab_b.T, annot=True, fmt="g", cmap='viridis', square = True, norm=LogNorm())
plt.show()

By archseries¶

# Remove unlimited
ocg_crosstab_c = pd.crosstab(exploded_archseries['Archseries'].where(exploded_archseries['OCG status']!='Unlimited'), exploded_archseries['OCG status'], margins = True)
ocg_crosstab_c

TCG vs. OCG status¶

cg_crosstab = pd.crosstab(formatted_full_df['OCG status'],formatted_full_df['TCG status'], dropna=False, margins = False)
cg_crosstab
plt.figure(figsize = (10,8))
sns.heatmap(cg_crosstab, annot=True, fmt="g", cmap='viridis', square=True, norm=LogNorm())
plt.show()

HTML export¶

! jupyter nbconvert Cards.ipynb --to=HTML --TemplateExporter.exclude_input_prompt=True --TemplateExporter.exclude_output_prompt=True

Searches¶

formatted_full_df.loc[formatted_full_df['OCG status'] == 'Not yet released'].loc[formatted_full_df['TCG status'] == 'Not yet released']

Git¶

! git add .
! git commit -m {"Update-" + pd.Timestamp.now().strftime("%d%m%Y")}
! git push